home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d985.lha / NewIFF / NewIFF39.lha / newiff39 / apps / Play8SVX / Play8SVX.c < prev    next >
C/C++ Source or Header  |  1993-09-28  |  25KB  |  837 lines

  1.  
  2. /** Play8SVX.c ************************************************************** 
  3.  * 
  4.  * Read and play sound sample from an IFF file.  21Jan85 
  5.  * 
  6.  * By Steve Hayes, Electronic Arts. 
  7.  * This software is in the public domain. 
  8.  * 
  9.  * Modified 05/91 for use with iffparse & to play notes - CAS_CBM
  10.  * requires linkage with several IFF modules - see Makefile
  11.  * 37.10 - checks for compression type, fails if unknown
  12.  *         changed "clock" variable to "tclock" to not override
  13.  *           some built-in variable of Manx's called "clock"
  14.  ****************************************************************************/ 
  15.  
  16. #include "iffp/8svxapp.h"
  17.  
  18. #include <exec/execbase.h>
  19. #include <graphics/gfxbase.h>
  20. #include <clib/alib_protos.h>
  21.  
  22.  
  23. #ifdef __SASC
  24. void __chkabort(void) {}          /* Disable SAS CTRL-C checking. */
  25. #else
  26. #ifdef LATTICE
  27. void chkabort(void) {}            /* Disable LATTICE CTRL-C checking */
  28. #endif
  29. #endif
  30.  
  31.  
  32. /* prototypes for our functions */
  33. void cleanup(void);
  34. void bye(UBYTE *s,int error);
  35. void DUnpack(BYTE source[], LONG n, BYTE dest[]);
  36. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x);
  37. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename);
  38. void UnloadSample(struct EightSVXInfo *esvx);
  39. LONG LoadSBody(struct EightSVXInfo *esvx);
  40. void UnloadSBody(struct EightSVXInfo *esvx);
  41.  
  42. LONG ShowSample(struct EightSVXInfo *esvx);
  43.  
  44. LONG OpenAudio(void);
  45. void CloseAudio(void);
  46. LONG PlaySample(struct EightSVXInfo *esvx,
  47.         LONG octave, LONG note, UWORD volume, ULONG delay);
  48.  
  49. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio *aio1,
  50.         BYTE *samptr, LONG ssize, ULONG period, UWORD volume);
  51.  
  52. #define MINARGS 2
  53.  
  54. #include "play8svx_rev.h"
  55. UBYTE vers[] = VERSTAG;
  56. UBYTE Copyright[] = VERS " - Play 8SVX Demo - Freely Redistributable";
  57.  
  58. char *usage = "Usage: Play8SVX 8SVXname";
  59.  
  60.  
  61. /* globals */
  62. struct Library *IFFParseBase   = NULL;
  63. struct Library *GfxBase = NULL;
  64.  
  65. BOOL   FromWb;
  66.  
  67. /* 8SVX Property chunks to be grabbed
  68.  */
  69. LONG    esvxprops[] = {
  70.         ID_8SVX, ID_VHDR,
  71.         ID_8SVX, ID_NAME,
  72.         ID_8SVX, ID_ATAK,
  73.         ID_8SVX, ID_RLSE,
  74.         ID_8SVX, ID_AUTH,
  75.         ID_8SVX, ID_Copyright,
  76.         TAG_DONE
  77.         };
  78.  
  79. /* 8SVX Collection chunks (more than one in file) to be gathered */
  80. LONG    esvxcollects[] = {
  81.         ID_8SVX, ID_ANNO,
  82.         TAG_DONE
  83.         };
  84.  
  85. /* 8SVX Chunk to stop on */
  86. LONG    esvxstops[] = {
  87.         ID_8SVX, ID_BODY,
  88.         TAG_DONE
  89.         };
  90.  
  91.  
  92. UBYTE nomem[]  = "Not enough memory\n";
  93. UBYTE noiffh[] = "Can't alloc iff\n";
  94.  
  95.  
  96.  
  97. /* For our allocated EightSVXInfo */
  98. struct EightSVXInfo  *esvx = NULL;
  99.  
  100.  
  101. /* 
  102.  * MAIN 
  103.  */
  104. void main(int argc, char **argv)
  105.    {
  106.    UBYTE *esvxname=NULL;
  107.    ULONG oct;
  108.    LONG error=0L;
  109.  
  110.    FromWb = argc ? FALSE : TRUE;
  111.  
  112.    if((argc<MINARGS)||(argv[argc-1][0]=='?'))
  113.     {
  114.     printf("%s\n%s\n",Copyright,usage);
  115.         bye("",RETURN_OK);
  116.     }
  117.  
  118.    esvxname = argv[1];
  119.  
  120. /* Open Libraries */
  121.    if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
  122.       bye("Can't open iffparse library.\n",RETURN_WARN);
  123.  
  124.  
  125. /* 
  126.  * Alloc one EightSVXInfo struct
  127.  */
  128.     if(!(esvx = (struct EightSVXInfo *)
  129.     AllocMem(sizeof(struct EightSVXInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
  130.         bye(nomem,RETURN_FAIL);
  131.  
  132. /*
  133.  * Here we set up our EightSVXInfo fields for our
  134.  * application.
  135.  * Above we have defined the propery and collection chunks
  136.  * we are interested in (some required like VHDR).
  137.  * We want to stop on BODY.
  138.  */
  139.     esvx->ParseInfo.propchks    = esvxprops;
  140.     esvx->ParseInfo.collectchks    = esvxcollects;
  141.     esvx->ParseInfo.stopchks    = esvxstops;
  142. /* 
  143.  * Alloc the IFF handle for the frame
  144.  */
  145.     if(!(esvx->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
  146.  
  147.  
  148.     if(!(error = LoadSample(esvx, esvxname)))
  149.     {
  150.     ShowSample(esvx);
  151.  
  152.     if(!(error = OpenAudio()))
  153.         {
  154.         /* If we think this is a sound effect, play it as such (note=-1) */
  155.         if((esvx->Vhdr.ctOctave==1)&&(esvx->Vhdr.samplesPerSec)
  156.         &&(esvx->Vhdr.oneShotHiSamples)&&(!esvx->Vhdr.repeatHiSamples))
  157.         {
  158.         PlaySample(esvx,0,-1,64,0);
  159.         }
  160.         /* Else play it like an instrument */
  161.         else
  162.         {
  163.             for(oct=0; oct < esvx->Vhdr.ctOctave; oct++)
  164.             {
  165.                 PlaySample(esvx,oct,0,64,50);
  166.                 PlaySample(esvx,oct,4,64,50);
  167.                 PlaySample(esvx,oct,7,64,50);
  168.             }
  169.         }
  170.         CloseAudio();
  171.         }
  172.         else printf("error opening audio device\n");
  173.     }
  174.     else
  175.         printf("%s\n",IFFerr(error));
  176.  
  177.     cleanup();
  178.     exit(RETURN_OK);
  179.     }
  180.  
  181.  
  182. void bye(UBYTE *s,int error)
  183.    {
  184.    if((*s)&&(!FromWb)) printf("%s\n",s);
  185.    cleanup();
  186.    exit(error);
  187.    }
  188.  
  189.  
  190. void cleanup()
  191.    {
  192.    if(esvx)        
  193.     {
  194.     DD(bug("About to UnloadSample\n"));
  195.     UnloadSample(esvx);
  196.  
  197.     DD(bug("About to FreeIFF\n"));
  198.     if(esvx->ParseInfo.iff)     FreeIFF(esvx->ParseInfo.iff);
  199.  
  200.     DD(bug("About to free EightSVXInfo\n"));
  201.         FreeMem(esvx,sizeof(struct EightSVXInfo));
  202.     }
  203.  
  204.    if(IFFParseBase)      CloseLibrary(IFFParseBase);
  205.    }
  206.  
  207.  
  208. /** ShowSample() **********************************************
  209.  * 
  210.  * Show sample information after calling LoadSample()
  211.  * 
  212.  *************************************************************************/
  213. LONG ShowSample(struct EightSVXInfo *esvx)
  214.     {
  215.     LONG error = 0L;
  216.     BYTE *buf;
  217.     Voice8Header *vhdr;
  218.  
  219.     if(!esvx)            return(CLIENT_ERROR);
  220.     if(!(buf = esvx->sample))    return(CLIENT_ERROR);
  221.  
  222.     /* LoadSample copied VHDR and NAME (if any) to our esvx frame */
  223.     vhdr = &esvx->Vhdr;
  224.     if(esvx->name[0]) printf("\nNAME: %s",esvx->name);
  225.  
  226.     printf("\n\nVHDR Info:");
  227.     printf("\noneShotHiSamples=%ld", vhdr->oneShotHiSamples); 
  228.     printf("\nrepeatHiSamples=%ld", vhdr->repeatHiSamples); 
  229.     printf("\nsamplesPerHiCycle=%ld", vhdr->samplesPerHiCycle); 
  230.     printf("\nsamplesPerSec=%ld", vhdr->samplesPerSec); 
  231.     printf("\nctOctave=%ld", vhdr->ctOctave); 
  232.     printf("\nsCompression=%ld", vhdr->sCompression); 
  233.     printf("\nvolume=0x%lx", vhdr->volume); 
  234.     printf("\nData = %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld",  
  235.            buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); 
  236.     printf("\n       %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld ...\n",  
  237.            buf[8+0],buf[8+1],buf[8+2],buf[8+3],buf[8+4],buf[8+5],
  238.            buf[8+6],buf[8+ 7]); 
  239.  
  240.     return(error);
  241.     } 
  242.  
  243.  
  244. /* OpenAudio
  245.  *
  246.  * Opens audio device for one audio channel, 2 IO requests
  247.  * Returns 0 for success
  248.  *
  249.  * Based on code by Dan Baker
  250.  */
  251.  
  252. UBYTE           whichannel[] = { 1,2,4,8 };
  253.  
  254. /* periods for scale starting at   65.40Hz (C) with 128 samples per cycle
  255.  *                            or  130.81Hz (C) with  64 samples per cycle
  256.  *                            or  261.63Hz (C) with  32 samples per cycle
  257.  *                            or  523.25Hz (C) with  16 samples per cycle
  258.  *                            or 1046.50Hz (C) with   8 samples per cycle
  259.  *                            or 2093.00Hz (C) with   4 samples per cycle
  260.  */
  261.  
  262. UWORD   per_ntsc[12]= { 428, 404, 380, 360,
  263.             340, 320, 302, 286,
  264.             270, 254, 240, 226 };
  265.  
  266. /* periods adjusted for system clock frequency */
  267. UWORD   per[12];
  268.  
  269. /* Note - these values 3579545 NTSC, 3546895 PAL */
  270. #define NTSC_CLOCK 3579545L
  271. #define PAL_CLOCK  3546895L
  272.  
  273. #define AIOCNT 4
  274. struct     IOAudio *aio[AIOCNT] = {NULL};       /* Ptrs to IO blocks for commands  */
  275.  
  276. struct     MsgPort *port;       /* Pointer to a port so the device can reply */
  277. BOOL    devopened;
  278. ULONG    tclock = NTSC_CLOCK;    /* Will check for PAL and change if necessary */
  279.  
  280.  
  281. LONG OpenAudio()
  282. {
  283. extern    struct ExecBase *SysBase;
  284. LONG     error=0L;
  285. ULONG   period;
  286. int    k;
  287.  
  288. if(devopened)    return(-1);
  289.  
  290. /*-------------------------------------------------------------------------*/
  291. /* Ask the system if we are PAL or NTSC and set clock constant accordingly */
  292. /*-------------------------------------------------------------------------*/
  293. if(GfxBase=OpenLibrary("graphics.library",0L))
  294.     {
  295.     if(((struct GfxBase *)GfxBase)->DisplayFlags & PAL)
  296.         tclock = PAL_CLOCK;
  297.     else
  298.         tclock = NTSC_CLOCK;
  299.     CloseLibrary((struct Library *) GfxBase);
  300.     }
  301.  
  302. printf("OpenAudio: For period calculations, tclock=%ld\n", tclock);
  303.  
  304. /* calculate period values for one octave based on system clock */
  305. for(k=0; k<12; k++)
  306.     {
  307.     period = ((per_ntsc[k] * tclock) + (NTSC_CLOCK >> 1)) / NTSC_CLOCK;
  308.     per[k] = period;
  309.     D(bug("per[%ld]=%ld ",k,per[k]));
  310.     }
  311. D(bug("\n"));
  312.  
  313. /*-------------------------------------------------------------------*/
  314. /* Create a reply port so the audio device can reply to our commands */
  315. /*-------------------------------------------------------------------*/
  316. if(!(port=CreatePort(0,0)))
  317.     { error = 1; goto bailout; }
  318.  
  319. /*--------------------------------------------------------------------------*/
  320. /*  Create audio I/O blocks so we can send commands to the audio device     */
  321. /*--------------------------------------------------------------------------*/
  322. for(k=0; k<AIOCNT; k++)
  323.     {
  324.     if(!(aio[k]=(struct IOAudio *)CreateExtIO(port,sizeof(struct IOAudio))))
  325.     { error = k+2; goto bailout; }
  326.     }
  327.  
  328. /*----------------------------------------------------------------------*/
  329. /* Set up the audio I/O block for channel allocation:                   */
  330. /* ioa_Request.io_Message.mn_ReplyPort is the address of a reply port.  */
  331. /* ioa_Request.io_Message.mn_Node.ln_Pri sets the precedence (priority) */
  332. /*   of our use of the audio device. Any tasks asking to use the audio  */
  333. /*   device that have a higher precedence will steal the channel from us.*/
  334. /* ioa_Request.io_Command is the command field for IO.                  */
  335. /* ioa_Request.io_Flags is used for the IO flags.                       */
  336. /* ioa_AllocKey will be filled in by the audio device if the allocation */
  337. /*   succeeds. We must use the key it gives for all other commands sent.*/
  338. /* ioa_Data is a pointer to the array listing the channels we want.     */
  339. /* ioa_Length tells how long our list of channels is.                   */
  340. /*----------------------------------------------------------------------*/
  341. aio[0]->ioa_Request.io_Command               = ADCMD_ALLOCATE;
  342. aio[0]->ioa_Request.io_Flags                 = ADIOF_NOWAIT;
  343. aio[0]->ioa_AllocKey                         = 0;
  344. aio[0]->ioa_Data                             = whichannel;
  345. aio[0]->ioa_Length                           = sizeof(whichannel);
  346.  
  347. /*-----------------------------------------------*/
  348. /* Open the audio device and allocate a channel  */
  349. /*-----------------------------------------------*/
  350. if(!(OpenDevice("audio.device",0L, (struct IORequest *) aio[0] ,0L)))
  351.     devopened = TRUE;
  352. else { error = 5; goto bailout; }
  353.  
  354. /* Clone the flags, channel allocation, etc. into other IOAudio requests */
  355. for(k=1; k<AIOCNT; k++)    *aio[k] = *aio[0];
  356.  
  357. bailout:
  358. if(error)    
  359.     {
  360.     printf("OpenAudio errored out at step %ld\n",error);
  361.     CloseAudio();
  362.     }
  363. return(error);
  364. }
  365.  
  366.  
  367. /* CloseAudio
  368.  *
  369.  * Close audio device as opened by OpenAudio, null out pointers
  370.  */
  371. void CloseAudio()
  372. {
  373. int k;
  374.  
  375. D(bug("Closing audio device...\n"));
  376.  
  377. /* Note - we know we have no outstanding audio requests */
  378. if(devopened)
  379.     {
  380.     CloseDevice((struct IORequest *) aio[0]);
  381.     devopened = FALSE;
  382.     }
  383.  
  384. for(k=0; k<AIOCNT; k++)
  385.     {
  386.     if(aio[k])     DeleteExtIO(aio[k]), aio[k] = NULL;
  387.     }
  388.  
  389. if(port)       DeletePort(port),  port = NULL;
  390. }
  391.  
  392.  
  393. /** PlaySample() **********************************************
  394.  * 
  395.  * Play a note in octave for delay/50ths of a second 
  396.  * OR Play a sound effect (set octave and note to 0, -1)
  397.  *
  398.  * Requires successful OpenAudio() called previously
  399.  *
  400.  * When playing notes:
  401.  * Expects note values between 0 (C) and 11 (B#)
  402.  * Uses largest octave sample in 8SVX as octave 0, next smallest
  403.  *   as octave 1, etc.
  404.  *
  405.  * Notes - this simple example routine does not do ATAK and RLSE)
  406.  *       - use of Delay for timing is simplistic, synchronous, and does
  407.  *        not take into account that the oneshot itself may be
  408.  *        longer than the delay.
  409.  *         Use timer.device for more accurate asynchronous delays
  410.  *
  411.  *************************************************************************/
  412. /* Max playable sample in one IO request is 128K */
  413. #define MAXSAMPLE 131072
  414.  
  415. LONG    PlaySample(struct EightSVXInfo *esvx,
  416.             LONG octave, LONG note, UWORD volume, ULONG delay)
  417. {
  418. /* pointers to outstanding requests */
  419. struct        IOAudio    *aout0=NULL, *aout1=NULL;    
  420. ULONG        period;
  421. LONG        osize, rsize;
  422. BYTE        *oneshot, *repeat;
  423.  
  424. if(!devopened)    return(-1);
  425.  
  426. if(note > 11) note=0;
  427.  
  428. if( note == -1 ) period = tclock / esvx->Vhdr.samplesPerSec;
  429. else          period = per[note]; /* table set up by OpenAudio */
  430.  
  431. if(octave > esvx->Vhdr.ctOctave) octave = 0;
  432. if(volume > 64)    volume = 64;
  433.  
  434. oneshot = esvx->osamps[octave];
  435. osize   = esvx->osizes[octave];
  436. repeat  = esvx->rsamps[octave];
  437. rsize   = esvx->rsizes[octave];
  438.  
  439. D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  440.     oneshot, osize, repeat, rsize));
  441.  
  442. /*------------------------------------------------------------*/
  443. /* Set up audio I/O blocks to play a sample using CMD_WRITE.  */
  444. /* Set up one request for the oneshot and one for repeat      */
  445. /* (all ready for simple case, but we may not need both)      */
  446. /* The io_Flags are set to ADIOF_PERVOL so we can set the     */
  447. /*    period (speed) and volume with the our sample;          */
  448. /* ioa_Data points to the sample; ioa_Length gives the length */
  449. /* ioa_Cycles tells how many times to repeat the sample       */
  450. /* If you want to play the sample at a given sampling rate,   */
  451. /* set ioa_Period = clock/(given sampling rate)               */
  452. /*------------------------------------------------------------*/
  453. aio[0]->ioa_Request.io_Command             =CMD_WRITE;
  454. aio[0]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  455. aio[0]->ioa_Data                           =oneshot;
  456. aio[0]->ioa_Length                         =osize;
  457. aio[0]->ioa_Period                         =period;
  458. aio[0]->ioa_Volume                         =volume;
  459. aio[0]->ioa_Cycles                         =1;
  460.  
  461. aio[2]->ioa_Request.io_Command             =CMD_WRITE;
  462. aio[2]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  463. aio[2]->ioa_Data                           =repeat;
  464. aio[2]->ioa_Length                         =rsize;
  465. aio[2]->ioa_Period                         =period;
  466. aio[2]->ioa_Volume                         =volume;
  467. aio[2]->ioa_Cycles                         =0;    /* repeat until stopped */
  468.  
  469. /*---------------------------------------------------*/
  470. /* Send the command to start a sound using BeginIO() */
  471. /* Go to sleep and wait for the sound to finish with */
  472. /* WaitIO() to wait and get the get the ReplyMsg     */
  473. /*---------------------------------------------------*/
  474. printf("Starting tone O len %ld for %0ld cyc, R len %ld for %0ld cyc, per=%ld...",
  475.         osize, aio[0]->ioa_Cycles, rsize, aio[1]->ioa_Cycles, period);
  476.  
  477. if(osize)
  478.     {
  479.     /* Simple case for oneshot sample <= 128K (ie. most samples) */
  480.     if(osize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout0=aio[0]));
  481.  
  482.     /* Note - this else case code is for samples >128K */
  483.     else
  484.     {
  485.     *aio[1] = *aio[0];
  486.     aout0 = playbigsample(aio[0],aio[1],oneshot,osize,period,volume);
  487.     }
  488.      }
  489.  
  490. if(rsize)
  491.     {
  492.     /* Simple case for repeat sample <= 128K (ie. most samples) */
  493.     if(rsize <= MAXSAMPLE)    BeginIO((struct IORequest *)(aout1=aio[2]));
  494.  
  495.     /* Note - this else case code is for samples >128K */
  496.     else
  497.     {
  498.     *aio[3] = *aio[2];
  499.     aout1 = playbigsample(aio[2],aio[3],repeat,rsize,period,volume);
  500.     }
  501.      }
  502.  
  503. if(delay)    Delay(delay);    /* crude timing for notes */
  504.  
  505. /* Wait for any requests we still have out */
  506. if(aout0) WaitIO(aout0);
  507.  
  508. if(aout1)
  509.    {
  510.    if(note >= 0) AbortIO(aout1);    /* if a note, stop it now */
  511.    WaitIO(aout1);
  512.    }
  513.  
  514. printf("Done\n");
  515. }
  516.  
  517.  
  518. /** playbigsample() ********************************************************
  519.  * 
  520.  *  called by playsample to deal with samples > 128K
  521.  *
  522.  *  wants pointers to two ready-to-use IOAudio iorequest blocks
  523.  *
  524.  *  returns pointer to the IOAudio request that is still out
  525.  *   or NULL if none (error)
  526.  *************************************************************************/
  527.  
  528. struct IOAudio *playbigsample(struct IOAudio *aio0, struct IOAudio* aio1,
  529.             BYTE *samptr, LONG ssize, ULONG period, UWORD volume)
  530. {
  531. struct IOAudio *aio[2];
  532. LONG   size;
  533. int    req=0, reqn=1;    /* current and next IOAudio request indexes */
  534.  
  535. if((!aio0)||(!aio1)||(ssize < MAXSAMPLE))    return(NULL);
  536.  
  537. aio[req]  = aio0;
  538. aio[reqn] = aio1;
  539.  
  540. /* start the first 128 K playing */
  541. aio[req]->ioa_Request.io_Command             =CMD_WRITE;
  542. aio[req]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  543. aio[req]->ioa_Data                           =samptr;
  544. aio[req]->ioa_Length                 =MAXSAMPLE;
  545. aio[req]->ioa_Period                         =period;
  546. aio[req]->ioa_Volume                         =volume;
  547. aio[req]->ioa_Cycles                         =1;
  548. BeginIO((struct IORequest*)aio[req]);
  549.  
  550. for(samptr=samptr + MAXSAMPLE, size = ssize - MAXSAMPLE;
  551.     size > 0;
  552.         samptr += MAXSAMPLE)
  553.     {
  554.     /* queue the next piece of sample */
  555.     reqn = req ^ 1;    /* alternate IO blocks 0 and 1 */
  556.     aio[reqn]->ioa_Request.io_Command             =CMD_WRITE;
  557.     aio[reqn]->ioa_Request.io_Flags               =ADIOF_PERVOL;
  558.     aio[reqn]->ioa_Data                           =samptr;
  559.     aio[reqn]->ioa_Length = (size > MAXSAMPLE) ? MAXSAMPLE : size;
  560.     aio[reqn]->ioa_Period                         =period;
  561.     aio[reqn]->ioa_Volume                         =volume;
  562.     aio[reqn]->ioa_Cycles                         =1;
  563.     BeginIO((struct IORequest*)aio[reqn]);
  564.  
  565.     /* Wait for previous request to finish */
  566.     WaitIO(aio[req]);
  567.     /* decrement size */
  568.     size = (size > MAXSAMPLE) ? size-MAXSAMPLE : 0;
  569.     req = reqn;        /* switch between aio[0] and aio[1] */
  570.     }
  571. return(aio[reqn]);
  572. }
  573.  
  574. /** LoadSample() **********************************************************
  575.  * 
  576.  * Read 8SVX, given an initialized EightSVXInfo with not-in-use IFFHandle,
  577.  *   and filename.  Leaves the IFFHandle open so you can FindProp()
  578.  *   additional chunks or copychunks().  You must UnloadSample()
  579.  *   when done.  UnloadSample will closeifile if the file is still
  580.  *   open.
  581.  *
  582.  * Fills in esvx->Vhdr and Name, and allocates/loads esvx->sample,
  583.  *   setting esvx->samplebytes to size for deallocation.
  584.  *
  585.  * Returns 0 for success of an IFFERR (libraries/iffparse.h)
  586.  *************************************************************************/
  587. LONG LoadSample(struct EightSVXInfo *esvx, UBYTE *filename)
  588.     {
  589.     struct IFFHandle *iff;
  590.     struct StoredProperty *sp;
  591.     Voice8Header *vhdr;
  592.     BYTE *oneshot, *repeat;
  593.     ULONG osize, rsize, spcyc;
  594.     int oct;
  595.     LONG error = 0L;
  596.  
  597.     D(bug("LoadSample:\n"));
  598.     
  599.     if(!esvx)                return(CLIENT_ERROR);
  600.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  601.  
  602.     if(!(error = openifile((struct ParseInfo *)esvx, filename, IFFF_READ)))
  603.     {
  604.     printf("Reading '%s'...\n",filename);
  605.     error = parseifile((struct ParseInfo *)esvx,
  606.             ID_FORM, ID_8SVX,
  607.             esvx->ParseInfo.propchks,
  608.             esvx->ParseInfo.collectchks,
  609.             esvx->ParseInfo.stopchks);
  610.  
  611.     D(bug("LoadSample: after parseifile - error = %ld\n",error));
  612.  
  613.     if((!error)||(error == IFFERR_EOC)||(error == IFFERR_EOF))
  614.         {
  615.         if(contextis(iff,ID_8SVX,ID_FORM))
  616.         {
  617.         D(bug("LoadSample: context is 8SVX\n"));
  618.         if(!(sp = FindProp(iff,ID_8SVX,ID_VHDR)))
  619.             {
  620.             message("No 8SVX.VHDR!");
  621.             error = IFFERR_SYNTAX;
  622.             }
  623.         else
  624.             {
  625.             D(bug("LoadSample: Have VHDR\n"));
  626.             /* copy Voice8Header into frame */
  627.             vhdr = (Voice8Header *)(sp->sp_Data);
  628.             *(&esvx->Vhdr) = *vhdr;
  629.             /* copy name if any */
  630.             esvx->name[0]='\0';
  631.             if(sp = FindProp(iff,ID_8SVX,ID_NAME))
  632.             {
  633.             strncpy(esvx->name,sp->sp_Data,sp->sp_Size);
  634.             esvx->name[MIN(sp->sp_Size,79)] = '\0';
  635.             }
  636.                 error = LoadSBody(esvx);
  637.             D(bug("LoadSample: After LoadSBody - error = %ld\n",error));
  638.             if(!error)
  639.             {
  640.             osize   = esvx->Vhdr.oneShotHiSamples;
  641.             rsize   = esvx->Vhdr.repeatHiSamples;
  642.             spcyc    = esvx->Vhdr.samplesPerHiCycle;
  643.             if(!spcyc) spcyc = esvx->Vhdr.repeatHiSamples;
  644.             if(!spcyc) spcyc = 8;
  645.  
  646.             oneshot = esvx->sample;
  647.  
  648.             for(oct = esvx->Vhdr.ctOctave-1; oct >= 0;
  649.                  oct--, oneshot+=(osize+rsize),
  650.                     osize <<= 1, rsize <<=1, spcyc <<=1)
  651.                     {
  652.                     repeat  = oneshot + osize;
  653.                 esvx->osizes[oct] = osize;
  654.                 if(osize) esvx->osamps[oct] = oneshot;
  655.                 else      esvx->osamps[oct] = 0;
  656.                 esvx->rsizes[oct] = rsize;
  657.                 if(rsize) esvx->rsamps[oct] = repeat;
  658.                 else      esvx->rsamps[oct] = 0;
  659.                 esvx->spcycs[oct] = spcyc;
  660.  
  661.              D(bug("oneshot $%lx size %ld, repeat $%lx size %ld\n",
  662.                 oneshot, osize, repeat, rsize));
  663.  
  664.                 }
  665.                 }
  666.             }
  667.         }
  668.         else
  669.         {
  670.         message("Not an 8SVX\n");
  671.         error = NOFILE;
  672.         }
  673.         }
  674.     }
  675.  
  676.     if(error)
  677.     {
  678.     closeifile((struct ParseInfo *)esvx);
  679.     UnloadSample(esvx);
  680.     }
  681.     return(error);
  682.     }
  683.  
  684.  
  685. /** UnloadSample() *******************************************************
  686.  * 
  687.  * Frees and closes everything opened/alloc'd by LoadSample()
  688.  *
  689.  *************************************************************************/
  690. void UnloadSample(struct EightSVXInfo *esvx)
  691.     {
  692.     if(esvx)
  693.     {
  694.     UnloadSBody(esvx);
  695.     closeifile((struct ParseInfo *)esvx);
  696.     }
  697.     }
  698.  
  699.  
  700. /** LoadSBody() ***********************************************************
  701.  * 
  702.  * Read a 8SVX Sample BODY into RAM.  
  703.  * 
  704.  *************************************************************************/
  705. LONG LoadSBody(struct EightSVXInfo *esvx)
  706.     {
  707.     struct IFFHandle *iff;
  708.     LONG sbytes, rlen, error = 0L; 
  709.     ULONG memtype;
  710.     Voice8Header *vhdr = &esvx->Vhdr;
  711.     BYTE *t;
  712.  
  713.     D(bug("LoadSBody:\n"));
  714.  
  715.     if(!(iff=esvx->ParseInfo.iff))    return(CLIENT_ERROR);
  716.     if(!esvx)                return(CLIENT_ERROR);
  717.  
  718.     if(!(currentchunkis(iff,ID_8SVX,ID_BODY)))
  719.     {
  720.     message("LoadSBody: not at BODY!");
  721.     return(IFFERR_READ);
  722.     }
  723.  
  724.     sbytes  = ChunkMoreBytes(CurrentChunk(iff)); 
  725.  
  726.     /* if we have to decompress, let's just load it into public mem */
  727.     memtype = vhdr->sCompression ? MEMF_PUBLIC : MEMF_CHIP;
  728.  
  729.     D(bug("LoadSBody: samplebytes=%ld, compression=%ld\n",
  730.             sbytes,vhdr->sCompression));
  731.     
  732.     if(!(esvx->sample = (BYTE *)AllocMem(sbytes, memtype))) 
  733.     {
  734.         error = IFFERR_NOMEM;    /* used to be flagged as client error */ 
  735.     }
  736.     else 
  737.     {
  738.     D(bug("LoadSBody: have load buffer\n"));
  739.     esvx->samplebytes = sbytes; 
  740.         if(rlen=ReadChunkBytes(iff,esvx->sample,sbytes) != sbytes)
  741.         error = IFFERR_READ;
  742.  
  743.     if(error)
  744.         {
  745.         D(bug("LoadSBody: ReadChunkBytes error = %ld, read %ld bytes\n",
  746.             error));
  747.         }
  748.     else if (vhdr->sCompression == sCmpFibDelta ) /* Decompress, if needed. */
  749.         {
  750.             if(t = (BYTE *)AllocMem(sbytes<<1, MEMF_CHIP)) 
  751.         {
  752.         D(bug("LoadSBody: have decompression buffer\n"));
  753.                 DUnpack(esvx->sample, sbytes, t); 
  754.                 FreeMem(esvx->sample, sbytes); 
  755.                 esvx->sample = t;
  756.                 esvx->samplebytes = sbytes << 1;
  757.         }
  758.         else
  759.         {
  760.         error = IFFERR_NOMEM;
  761.         }
  762.         } 
  763.     else if (vhdr->sCompression)    /* unknown ompression method */
  764.         {
  765.         error = CLIENT_ERROR;
  766.         }
  767.     }
  768.     if(error)    UnloadSample(esvx);
  769.     return(error);
  770.     } 
  771.  
  772.  
  773. /** UnloadSBody() ********************************************************
  774.  * 
  775.  * Deallocates esvx->smaple  
  776.  * 
  777.  *************************************************************************/
  778. void UnloadSBody(struct EightSVXInfo *esvx)
  779.     {
  780.     if(esvx)
  781.     {
  782.     if(esvx->sample)
  783.         {
  784.         DD(bug("About to free SBody\n"));
  785.         FreeMem(esvx->sample,esvx->samplebytes);
  786.         esvx->sample = NULL;
  787.         }
  788.     esvx->samplebytes = NULL;
  789.     }
  790.     }
  791.  
  792.  
  793. /* DUnpack.c --- Fibonacci Delta decompression by Steve Hayes */
  794.  
  795. /* Fibonacci delta encoding for sound data */
  796. BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
  797.  
  798. /* Unpack Fibonacci-delta encoded data from n byte source
  799.  * buffer into 2*n byte dest buffer, given initial data
  800.  * value x.  It returns the lats data value x so you can
  801.  * call it several times to incrementally decompress the data.
  802.  */
  803.  
  804. BYTE D1Unpack(BYTE source[], LONG n, BYTE dest[], BYTE x)
  805.    {
  806.    BYTE d;
  807.    LONG i, lim;
  808.  
  809.    lim = n << 1;
  810.    for (i=0; i < lim; ++i)
  811.       {
  812.       /* Decode a data nibble, high nibble then low nibble */
  813.       d = source[i >> 1];    /* get a pair of nibbles */
  814.       if (i & 1)             /* select low or high nibble */
  815.          d &= 0xf;           /* mask to get the low nibble */
  816.       else
  817.          d >>= 4;            /* shift to get the high nibble */
  818.       x += codeToDelta[d];   /* add in the decoded delta */
  819.       dest[i] = x;           /* store a 1 byte sample */
  820.       }
  821.    return(x);
  822.    }
  823.  
  824. /* Unpack Fibonacci-delta encoded data from n byte
  825.  * source buffer into 2*(n-2) byte dest buffer.
  826.  * Source buffer has a pad byte, an 8-bit initial
  827.  * value, followed by n-2 bytes comprising 2*(n-2)
  828.  * 4-bit encoded samples.
  829.  */
  830.  
  831. void DUnpack(source, n, dest)
  832. BYTE source[], dest[];
  833. LONG n;
  834.    {
  835.    D1Unpack(source+2, n-2, dest, source[1]);
  836.    }
  837.